package com.fita.api.handler.impl;

import java.io.File;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.ws.BindingProvider;

import org.apache.commons.lang3.StringUtils;
import org.opentravel.ota._2003._05.AddressInfoType;
import org.opentravel.ota._2003._05.FormattedTextType;
import org.opentravel.ota._2003._05.OTAVehAvailRateRQ;
import org.opentravel.ota._2003._05.OTAVehAvailRateRS;
import org.opentravel.ota._2003._05.OTAVehCancelRQ;
import org.opentravel.ota._2003._05.OTAVehCancelRS;
import org.opentravel.ota._2003._05.OTAVehLocDetailRQ;
import org.opentravel.ota._2003._05.OTAVehLocDetailRS;
import org.opentravel.ota._2003._05.OTAVehLocSearchRQ;
import org.opentravel.ota._2003._05.OTAVehLocSearchRS;
import org.opentravel.ota._2003._05.OTAVehResRQ;
import org.opentravel.ota._2003._05.OTAVehResRS;
import org.opentravel.ota._2003._05.OperationScheduleType;
import org.opentravel.ota._2003._05.OperationScheduleType.OperationTimes.OperationTime;
import org.opentravel.ota._2003._05.StateProvType;
import org.opentravel.ota._2003._05.VehicleAvailCoreType;
import org.opentravel.ota._2003._05.VehicleChargePurposeType;
import org.opentravel.ota._2003._05.VehicleChargeType;
import org.opentravel.ota._2003._05.VehicleLocationDetailsType;
import org.opentravel.ota._2003._05.VehicleLocationInformationType;
import org.opentravel.ota._2003._05.VehicleLocationServicesOfferedType;
import org.opentravel.ota._2003._05.VehicleResRSCoreType;
import org.opentravel.ota._2003._05.VehicleVendorAvailabilityType.VehAvails.VehAvail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.demo2do.core.entity.exception.BusinessException;
import com.demo2do.core.entity.page.Page;
import com.demo2do.core.utils.DateFormatUtils;
import com.demo2do.core.utils.JsonUtils;
import com.erac.odyssey.webservice.ota.OTA30;
import com.erac.odyssey.webservice.ota.OTA30_Service;
import com.fita.api.dto.request.CancelExistingVehicleReservationRequest;
import com.fita.api.dto.request.LocationDetailRequest;
import com.fita.api.dto.request.LocationSearchRequest;
import com.fita.api.dto.request.VehicleReservationRequest;
import com.fita.api.dto.request.VehicleSearchRequest;
import com.fita.api.handler.WebserviceHandler;
import com.fita.entity.dto.ehi.response.LocationDetailResponse;
import com.fita.entity.dto.ehi.response.LocationSchedule;
import com.fita.entity.dto.ehi.response.LocationTelephone;
import com.fita.entity.dto.ehi.response.ReservationFees;
import com.fita.entity.dto.ehi.response.ReservationVehRentLocInfo;
import com.fita.entity.dto.ehi.response.ReservationVehicleCharges;
import com.fita.entity.dto.ehi.response.ReservationVendorMessage;
import com.fita.entity.dto.ehi.response.SpecialEquipment;
import com.fita.entity.dto.ehi.response.VehicleCore;
import com.fita.entity.dto.ehi.response.VehicleCoreCharge;
import com.fita.entity.dto.ehi.response.VehicleCoreFee;
import com.fita.entity.dto.ehi.response.VehicleReservationCancleResponse;
import com.fita.entity.dto.ehi.response.VehicleReservationResponse;
import com.fita.entity.dto.ehi.response.VehicleSearchResponse;

/**
 *
 * @author Ark
 *
 */
@Component("webserviceHandlerImpl")
public class WebserviceHandlerImpl implements WebserviceHandler  {
    
    private static final Logger logger = LoggerFactory.getLogger(WebserviceHandler.class);
    
    @Value("#{config['api.env']}")
    private String env;
    
    @Value("#{config['api.xml.filepath']}")
    private String filepath;
    
    /* (non-Javadoc)
     * @see com.fita.api.handler.WebserviceHandler#searchAvailableVehicle(com.fita.api.dto.request.VehicleSearchRequest, com.demo2do.core.entity.page.Page)
     */
    public VehicleSearchResponse searchAvailableVehicle(VehicleSearchRequest request, Page page) throws JAXBException {

        // valid
        if (!request.isValid()) {
            throw BusinessException.newInstance("400", "请求参数不合法");
        }
        
        request.initialize(env);
        
        try {
            // call webService
            OTA30 otaService = this.generateOta30();
            OTAVehAvailRateRQ otaRequest;
            otaRequest = request.generateRq();
            JAXBContext context = JAXBContext.newInstance(OTAVehAvailRateRQ.class);
            Marshaller marshaller = context.createMarshaller();
            
            marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            
            Date date = new Date();
            String dateTime = DateFormatUtils.format(date, "yyyy-MM-dd&HH:mm:SS");
            logger.info("start search at [{}]", dateTime);
            marshaller.marshal(otaRequest, new File(filepath + "/AvailableVehicle/VSR_RQ_" + dateTime + ".xml"));
            OTAVehAvailRateRS rs = otaService.otaVehAvailRate(otaRequest);
            marshaller.marshal(rs, new File(filepath + "/AvailableVehicle/VSR_RS_" + dateTime + ".xml"));

            logger.info("get rs [{}]", JsonUtils.toJson(rs));
            
            if(rs.getErrors() != null) {
                logger.error("search occurs error with rs [{}]", JsonUtils.toJson(rs));
                throw BusinessException.newInstance(rs.getErrors().getError().get(0).getCode(),rs.getErrors().getError().get(0).getValue());
            }
            
            List<VehicleCore> vehicleCores = new ArrayList<VehicleCore>();
            List<VehAvail> vehAvails = rs.getVehAvailRSCore().getVehVendorAvails().getVehVendorAvail().get(0).getVehAvails().getVehAvail();
            for(VehAvail vehVendorAvail : vehAvails) {
                logger.info("#WebserviceHandlerImpl generateVehicleCore() VehAvail [{}]",JsonUtils.toJson(vehVendorAvail));
                VehicleCore vehicleCore = this.generateVehicleCore(vehVendorAvail);
                vehicleCores.add(vehicleCore);
            }
            
            VehicleSearchResponse response = new VehicleSearchResponse();
            response.setVehicleCores(vehicleCores);
            logger.info("get response [{}]", JsonUtils.toJson(response));
            return response;
        } catch (ParserConfigurationException e) {
            logger.error("do search occurs error");
            return null;
        }
    }
    
    /**
     * 
     * @param vehAvail
     * @return
     */
    private VehicleCore generateVehicleCore(VehAvail vehAvail) {
        
        
        VehicleAvailCoreType core = vehAvail.getVehAvailCore();
        String categoryCode = core.getVehicle().getVehType().getVehicleCategory();
        String doorCount = core.getVehicle().getVehType().getDoorCount();
        String sizeCode = core.getVehicle().getVehClass().getSize();
        Boolean airConditionIn = core.getVehicle().isAirConditionInd();
        String transmissionType = core.getVehicle().getTransmissionType().name();
        String modalName = core.getVehicle().getVehMakeModel().getName();
        String modalCode = core.getVehicle().getVehMakeModel().getCode();
        String picture = core.getVehicle().getPictureURL();
        String passengerQuantity = core.getVehicle().getPassengerQuantity();
        Integer baggageQuantity = core.getVehicle().getBaggageQuantity() != null ? core.getVehicle().getBaggageQuantity().intValue() : null;
        BigDecimal totalAmount = core.getTotalCharge().get(0).getRateTotalAmount();
        BigDecimal esimatedTotalAmount = core.getTotalCharge().get(0).getEstimatedTotalAmount();
        String currencyCode = core.getTotalCharge().get(0).getCurrencyCode();
        String rateQualifier = !core.getRentalRate().isEmpty() ? core.getRentalRate().get(0).getRateQualifier().getRateQualifier() : "";
        
        VehicleCore vehicleCore = new VehicleCore(categoryCode , sizeCode , doorCount, airConditionIn ,
                transmissionType ,modalName ,modalCode ,picture ,
                passengerQuantity , baggageQuantity , totalAmount ,
                esimatedTotalAmount ,currencyCode, rateQualifier);
        
        VehicleAvailCoreType.Reference refrence = core.getReference();
        if(refrence != null) {
            String referenceId = refrence.getID();
            Date referenceDate = refrence.getDateTime().toGregorianCalendar().getTime();
            String type = refrence.getType();
            vehicleCore.bindReference(referenceId, referenceDate, type);
        }
        
        
        if(core.getRentalRate().get(0).getVehicleCharges() != null && !core.getRentalRate().get(0).getVehicleCharges().getVehicleCharge().isEmpty()) {
        	
        	List<VehicleCoreCharge> vehicleCharges = new ArrayList<VehicleCoreCharge>();
        	
        	List<VehicleChargePurposeType> vehicleChargesType = core.getRentalRate().get(0).getVehicleCharges().getVehicleCharge();
        	
        	for(VehicleChargePurposeType vehicleChargeType : vehicleChargesType ) {
        		
        	    if (vehicleChargeType.getCalculation().isEmpty()) {
                    continue;
                }
        		String purpose = vehicleChargeType.getPurpose();
        		Boolean  taxInclusive = vehicleChargeType.isTaxInclusive();
				String description = vehicleChargeType.getDescription();
				String ChargecurrencyCode = vehicleChargeType.getCurrencyCode();
				BigDecimal amount = vehicleChargeType.getAmount();
				BigDecimal unitCharge = vehicleChargeType.getCalculation().get(0).getUnitCharge();
				String unitName = vehicleChargeType.getCalculation().get(0).getUnitName();
				Integer quantity = vehicleChargeType.getCalculation().get(0).getQuantity();
				
				
				VehicleCoreCharge vehicleCoreCharge = new VehicleCoreCharge(purpose,taxInclusive,description,ChargecurrencyCode,amount,unitCharge,unitName,quantity);
        		
				vehicleCharges.add(vehicleCoreCharge);
        	}
        	
        	vehicleCore.bindVehicleCoreCharges(vehicleCharges);
        	
        }
        
        
        if(core.getFees() != null && core.getFees().getFee() != null && !core.getFees().getFee().isEmpty()) {
            
            List<VehicleCoreFee> fees = new ArrayList<VehicleCoreFee>();
            
            List<VehicleChargePurposeType> feesType = core.getFees().getFee();
            for(VehicleChargePurposeType feeType : feesType) {

                logger.info("#1 generateVehicleCore() description [{}] includedInRate [{}]",feeType.getDescription(),feeType.isIncludedInRate());
                String purpose= feeType.getPurpose();
                String description= feeType.getDescription();
                BigDecimal amount = feeType.getAmount();
                Boolean includedInRate = feeType.isIncludedInRate();
                String feeCurrencyCode = feeType.getCurrencyCode();
                
                VehicleCoreFee vehicleCoreFee = new VehicleCoreFee(purpose, description, includedInRate, amount, feeCurrencyCode);
                fees.add(vehicleCoreFee);
            }
            vehicleCore.bindFees(fees);
        }
        
        
        
        return vehicleCore;
    }
    
    
/***
 * @author LZJ
 * 
 * reservation
 * 
 */
    
  
    
     
    
    /*
     * (non-Javadoc)
     * @see com.fita.api.handler.WebserviceHandler#reservationVehicle(com.fita.api.dto.request.VehicleReservationRequest)
     */
    public VehicleReservationResponse reservationVehicle(VehicleReservationRequest request) throws JAXBException, ParserConfigurationException {
        
    	logger.info("request data at [{}]", JsonUtils.toJson(request));
    	
        // valid
        if (!request.isValid()) {
            throw BusinessException.newInstance("400", "请求参数不合法");
        }
        
        request.initialize(env);
        
        // call webService
        OTA30 otaService = this.generateOta30();
        OTAVehResRQ otaRequest = request.generesRq();
        
        JAXBContext context = JAXBContext.newInstance(OTAVehResRQ.class);
        Marshaller marshaller = context.createMarshaller();
        
        marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        
        //返回结果保存到xml
        Date date = new Date();
        String dateTime = DateFormatUtils.format(date, "yyyy-MM-dd&HH:mm:SS");
        logger.info("start search at [{}]", dateTime);
        marshaller.marshal(otaRequest, new File(filepath + "/Reservation/RQ/RV_RQ_" + dateTime + ".xml"));
        OTAVehResRS rs =  otaService.otaVehRes(otaRequest);
        
        marshaller.marshal(rs, new File(filepath + "/Reservation/RS/RV_RS_" + dateTime + ".xml"));
        
        marshaller.marshal(otaRequest, System.out);
        
        
        logger.info("get rs [{}]", JsonUtils.toJson(rs));
        
        if(rs.getErrors() != null) {
            logger.error("search occurs error with rs [{}]", JsonUtils.toJson(rs));
            throw BusinessException.newInstance(rs.getErrors().getError().get(0).getCode(), rs.getErrors().getError().get(0).getValue());
        }
        

        
        VehicleReservationResponse response = this.generateVehicleReservation(rs);

        
        return response;
    }
    
    
    @SuppressWarnings("static-access")
    public VehicleReservationResponse generateVehicleReservation(OTAVehResRS rs) {
        
            VehicleReservationResponse response = null;
            
            String confID = null;
            
            try {
                VehicleResRSCoreType core = rs.getVehResRSCore();
                
                confID = core.getVehReservation().getVehSegmentCore().getConfID().get(0).getID();
       
                String givenName =   core.getVehReservation().getCustomer().getPrimary().getPersonName().get(0).getGivenName().get(0);
                String surname =    core.getVehReservation().getCustomer().getPrimary().getPersonName().get(0).getSurname();
                String phoneNumber =  core.getVehReservation().getCustomer().getPrimary().getTelephone() != null && 
                                      !core.getVehReservation().getCustomer().getPrimary().getTelephone().isEmpty() ? 
                        core.getVehReservation().getCustomer().getPrimary().getTelephone().get(0).getPhoneNumber() : null;
                String email = core.getVehReservation().getCustomer().getPrimary().getEmail().get(0).getValue();
                String addressLine = core.getVehReservation().getCustomer().getPrimary().getAddress() != null &&
                                     !core.getVehReservation().getCustomer().getPrimary().getAddress().isEmpty() && 
                                     core.getVehReservation().getCustomer().getPrimary().getAddress().get(0).getAddressLine() != null && 
                                     !core.getVehReservation().getCustomer().getPrimary().getAddress().get(0).getAddressLine().isEmpty() ? 
                                     core.getVehReservation().getCustomer().getPrimary().getAddress().get(0).getAddressLine().get(0) : null;
                String cityName = core.getVehReservation().getCustomer().getPrimary().getAddress().get(0).getCityName();
                String postalCode = core.getVehReservation().getCustomer().getPrimary().getAddress().get(0).getPostalCode();
                StateProvType stateProv = core.getVehReservation().getCustomer().getPrimary().getAddress().get(0).getStateProv();
                String stateCode = stateProv == null ? "" : stateProv.getStateCode();
                String countryName = core.getVehReservation().getCustomer().getPrimary().getAddress().get(0).getCountryName().getCode();
                
                String membershipID =  null;
                String travelSector = null;
                String programID = null;
                String loyalLevel =null;
                if(core.getVehReservation().getCustomer().getPrimary().getCustLoyalty() != null && !core.getVehReservation().getCustomer().getPrimary().getCustLoyalty().isEmpty()) {
                    membershipID =  core.getVehReservation().getCustomer().getPrimary().getCustLoyalty().get(0).getMembershipID();
                    travelSector = core.getVehReservation().getCustomer().getPrimary().getCustLoyalty().get(0).getTravelSector();
                    programID = core.getVehReservation().getCustomer().getPrimary().getCustLoyalty().get(0).getProgramID();
                    loyalLevel =core.getVehReservation().getCustomer().getPrimary().getCustLoyalty().get(0).getLoyalLevel();
                }
                
                //TPAExtensions 自定义element
                
//            String rentalDuration = core.getVehReservation().getCustomer().getPrimary().getTPAExtensions().getAny().get(0).getAttribute("RentalDuration");
//            String number = core.getVehReservation().getCustomer().getPrimary().getTPAExtensions().getAny().get(1).getAttribute("Number");
//            String operatingCompanycCode = core.getVehReservation().getCustomer().getPrimary().getTPAExtensions().getAny().get(1).;
                
                String confType =  core.getVehReservation().getVehSegmentCore().getConfID().get(0).getType();
                String vendorCode =   core.getVehReservation().getVehSegmentCore().getVendor().getCode();
                String companyShortName = core.getVehReservation().getVehSegmentCore().getVendor().getCompanyShortName();
                Date pickUpDateTime = core.getVehReservation().getVehSegmentCore().getVehRentalCore().getPickUpDateTime().toGregorianCalendar().getTime();
                Date returnDateTime = core.getVehReservation().getVehSegmentCore().getVehRentalCore().getReturnDateTime().toGregorianCalendar().getTime();
                String pickUpLocationCode = core.getVehReservation().getVehSegmentCore().getVehRentalCore().getPickUpLocation().get(0).getLocationCode();
                String returnLocationCode = core.getVehReservation().getVehSegmentCore().getVehRentalCore().getReturnLocation().getLocationCode();

                String transmissionType = core.getVehReservation().getVehSegmentCore().getVehicle().getTransmissionType().AUTOMATIC.value();
                Boolean airConditionInd = core.getVehReservation().getVehSegmentCore().getVehicle().isAirConditionInd();
                BigInteger baggageQuantity = core.getVehReservation().getVehSegmentCore().getVehicle().getBaggageQuantity();
                String passengerQuantity = core.getVehReservation().getVehSegmentCore().getVehicle().getPassengerQuantity();
                String vehicleCategory = core.getVehReservation().getVehSegmentCore().getVehicle().getVehType().getVehicleCategory();
                String size = core.getVehReservation().getVehSegmentCore().getVehicle().getVehClass().getSize();
                String vehMakeModelName = core.getVehReservation().getVehSegmentCore().getVehicle().getVehMakeModel().getName();
                String vehMakeModelCode = core.getVehReservation().getVehSegmentCore().getVehicle().getVehMakeModel().getCode();
                String pictureURL = core.getVehReservation().getVehSegmentCore().getVehicle().getPictureURL();
                
                String vehiclePeriodUnitName = core.getVehReservation().getVehSegmentCore().getRentalRate().getRateDistance().get(0).getVehiclePeriodUnitName().YEAR.value();
                String distUnitName = core.getVehReservation().getVehSegmentCore().getRentalRate().getRateDistance().get(0).getDistUnitName().MILE.value();
                Boolean unlimited = core.getVehReservation().getVehSegmentCore().getRentalRate().getRateDistance().get(0).isUnlimited();
                
                List<ReservationVehicleCharges> vehicleCharges = new ArrayList<ReservationVehicleCharges>();
                
                List<VehicleChargePurposeType> vehicleChargesTypes =  core.getVehReservation().getVehSegmentCore().getRentalRate().getVehicleCharges().getVehicleCharge();
                
                for (VehicleChargePurposeType vehicleCharge : vehicleChargesTypes) {
                    
                    BigDecimal amount = vehicleCharge.getAmount();
                            
                    String currencyCode = vehicleCharge.getCurrencyCode();
                    
                    boolean taxInclusive = vehicleCharge.isTaxInclusive();
                    
                    String purpose = vehicleCharge.getPurpose();
                    
                    String description = vehicleCharge.getDescription();
   
                    BigDecimal unitCharge = vehicleCharge.getCalculation().get(0).getUnitCharge();
                    
                    String unitName = vehicleCharge.getCalculation().get(0).getUnitName();
                    
                    Integer Quantity = vehicleCharge.getCalculation().get(0).getQuantity();
                    
                    ReservationVehicleCharges vehCharge = new ReservationVehicleCharges (amount,currencyCode,taxInclusive,purpose,description,unitCharge,unitName,Quantity);
                    
                    vehicleCharges.add(vehCharge);
                    
                }
                
                String corpDiscountNmbr = core.getVehReservation().getVehSegmentCore().getRentalRate().getRateQualifier().getCorpDiscountNmbr();
                String rateQualifier = core.getVehReservation().getVehSegmentCore().getRentalRate().getRateQualifier().getRateQualifier();
                String ratePeriod = core.getVehReservation().getVehSegmentCore().getRentalRate().getRateQualifier().getRatePeriod().value();
                //测试有返回值，生产没有返回值
//            Boolean required = core.getVehReservation().getVehSegmentCore().getPricedEquips().getPricedEquip().get(0).isRequired();
//            String equipType = core.getVehReservation().getVehSegmentCore().getPricedEquips().getPricedEquip().get(0).getEquipment().getEquipType();
//            BigInteger equipmentQuantity = core.getVehReservation().getVehSegmentCore().getPricedEquips().getPricedEquip().get(0).getEquipment().getQuantity();
//            BigDecimal chargeAmount = core.getVehReservation().getVehSegmentCore().getPricedEquips().getPricedEquip().get(0).getCharge().getAmount();
//            Boolean guaranteedInd = core.getVehReservation().getVehSegmentCore().getPricedEquips().getPricedEquip().get(0).getCharge().isGuaranteedInd();
//            Boolean chargeIncludedInRate = core.getVehReservation().getVehSegmentCore().getPricedEquips().getPricedEquip().get(0).getCharge().isIncludedInRate();
//            Boolean includedInEstTotalInd = core.getVehReservation().getVehSegmentCore().getPricedEquips().getPricedEquip().get(0).getCharge().isIncludedInEstTotalInd();
//            String chargeCurrencyCode = core.getVehReservation().getVehSegmentCore().getPricedEquips().getPricedEquip().get(0).getCharge().getCurrencyCode();
                
                List<ReservationFees> fees =  new ArrayList<ReservationFees>();
                
                if (core.getVehReservation().getVehSegmentCore().getFees() != null) {
                	
                	List <VehicleChargePurposeType>  feeTypes = core.getVehReservation().getVehSegmentCore().getFees().getFee();

                    if (feeTypes != null && !feeTypes.isEmpty()){

                        for (VehicleChargePurposeType feeType : feeTypes) {

                            String currencyCode = feeType.getCurrencyCode();

                            //Boolean includedInRate =  feeType.isIncludedInRate();
                            Boolean taxInclusive =  feeType.isTaxInclusive();

                            BigDecimal amount  =  feeType.getAmount();

                            String description  = feeType.getDescription();
                            String  purpose  = feeType.getPurpose();

                            ReservationFees  fee = new ReservationFees(currencyCode,taxInclusive,amount,description,purpose);

                            fees.add(fee);
                        }
                    }else {
                        fees = null;
                    }

                }
                
                BigDecimal  rateTotalAmount  = core.getVehReservation().getVehSegmentCore().getTotalCharge().getRateTotalAmount();
                BigDecimal  estimatedTotalAmount  =    core.getVehReservation().getVehSegmentCore().getTotalCharge().getEstimatedTotalAmount();
                String totalChargeCurrencyCode = core.getVehReservation().getVehSegmentCore().getTotalCharge().getCurrencyCode();
                
                List<ReservationVendorMessage> vendorMessages = new ArrayList<ReservationVendorMessage>();
                
                List<FormattedTextType> textTypes = core.getVehReservation().getVehSegmentInfo().getVendorMessages().getVendorMessage();
                
                for(FormattedTextType textType : textTypes) {
                    
                    String title = textType.getTitle();
                    
                    //找不到对应的text
                    String text = textType.getSubSection().get(0).getParagraph().get(0).getName();
                    
                    ReservationVendorMessage message = new ReservationVendorMessage( title,  text);
                    
                    vendorMessages.add(message);
                    
                }
                List<ReservationVehRentLocInfo> vehRentLocInfos = new ArrayList<ReservationVehRentLocInfo>();         
                
                List<VehicleLocationInformationType> vehRentLocInfoTypes =   core.getVehReservation().getVehSegmentInfo().getLocationDetails().get(0).getAdditionalInfo().getVehRentLocInfos().getVehRentLocInfo();
                
                for(VehicleLocationInformationType vehRentLocInfoType : vehRentLocInfoTypes) {
                    
                     String title = vehRentLocInfoType.getTitle();
                    
                     String type = vehRentLocInfoType.getType();
                    
                     String subCode = vehRentLocInfoType.getSubSection().get(0).getSubCode();
                    
                     //找不到对应的text
                     //String text = vehRentLocInfoType.getSubSection().get(0).getParagraph().get(0).getName();             
                     ReservationVehRentLocInfo loc = new ReservationVehRentLocInfo( title,  type,  subCode,  null);
                    
                     vehRentLocInfos.add(loc);
                }
                response = new VehicleReservationResponse( givenName,  surname,  phoneNumber,  email,  addressLine,
                     cityName,  postalCode,  stateCode,  countryName,  membershipID,
                     travelSector,  programID,  loyalLevel,  null,  null,
                     null,  confType,  confID,  vendorCode,
                     companyShortName,  pickUpDateTime,  returnDateTime,  pickUpLocationCode,
                     returnLocationCode,  transmissionType,  airConditionInd,  baggageQuantity,
                     passengerQuantity,  vehicleCategory,  size,  vehMakeModelName,
                     vehMakeModelCode,  pictureURL,  vehiclePeriodUnitName,  distUnitName,
                     unlimited,  vehicleCharges,  corpDiscountNmbr,
                     rateQualifier,  ratePeriod, fees,
                     rateTotalAmount,  estimatedTotalAmount,  totalChargeCurrencyCode,
                     vendorMessages,  vehRentLocInfos);
            } catch (Exception e) {
                
                logger.error("#generateVehicleReservation() has exception [{}]", e);
                
                if (StringUtils.isNotBlank(confID)) {
                    response.setConfID(confID);
                    return response;
                }else {
                    throw e;
                }
            }
         
        return response;
    }
    
    
    
    /*
     * (non-Javadoc)
     * @see com.fita.api.handler.WebserviceHandler#searchLocation(com.fita.api.dto.request.LocationSearchRequest, com.demo2do.core.entity.page.Page)
     */
    public OTAVehLocSearchRS searchLocation(LocationSearchRequest request, Page page) throws JAXBException {
        
        // valid
        if (!request.isValid()) {
            throw BusinessException.newInstance("400", "请求参数不合法");
        }
        
        request.initialize(env);
        
        // call webService
        OTA30 otaService = this.generateOta30();
        OTAVehLocSearchRQ otaRequest = request.geneLocSecRq();
        
        JAXBContext context = JAXBContext.newInstance(OTAVehResRQ.class);
        Marshaller marshaller = context.createMarshaller();
        
        marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        
        marshaller.marshal(otaRequest, System.out);
        
        return otaService.otaVehLocSearch(otaRequest);
        
        
        
    }
    
    

    /*
     * (non-Javadoc)
     * @see com.fita.api.handler.WebserviceHandler#locationDetail(com.fita.api.dto.request.LocationDetailRequest, com.demo2do.core.entity.page.Page)
     */
    public LocationDetailResponse locationDetail(LocationDetailRequest request, Page page) throws JAXBException, ParserConfigurationException {
        
        // valid
        if (!request.isValid()) {
            throw BusinessException.newInstance("400", "请求参数不合法");
        }
        
        request.initialize(env);
        
        // call webService
        OTA30 otaService = this.generateOta30();
        OTAVehLocDetailRQ otaRequest = request.geneLocDeRq();
        
        JAXBContext context = JAXBContext.newInstance(OTAVehResRQ.class);
        Marshaller marshaller = context.createMarshaller();
        
        marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        
        marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        
        Date date = new Date();
        String dateTime = DateFormatUtils.format(date, "yyyy-MM-dd&HH:mm:SS");
        logger.info("start search at [{}]", dateTime);
        marshaller.marshal(otaRequest, new File(filepath + "/LocationDetail/LD_RQ_" + dateTime + ".xml"));
        OTAVehLocDetailRS rs = otaService.otaVehLocDetail(otaRequest);
        marshaller.marshal(rs, new File(filepath + "/LocationDetail/LD_RS_" + dateTime + ".xml"));
        
        logger.info("get rs [{}]", JsonUtils.toJson(rs));
        
        if(rs.getErrors() != null) {
            logger.error("Detail occurs error with rs [{}]", JsonUtils.toJson(rs));
            throw BusinessException.newInstance(rs.getErrors().getError().get(0).getCode(), rs.getErrors().getError().get(0).getValue());
        }
        
        LocationDetailResponse response = this.generateLocationDetailResponse(rs);
        
        logger.info("get response [{}]", JsonUtils.toJson(response));
        
        return response;
    }
    
    /**
     * 
     * @param rs
     * @return
     */
    private LocationDetailResponse generateLocationDetailResponse(OTAVehLocDetailRS rs) {
        
        LocationDetailResponse response = new LocationDetailResponse();
        
        VehicleLocationDetailsType detail = rs.getLocationDetail();
        
        response.setName(detail.getName());
        response.setCode(detail.getCode());
        response.setAtAirport(detail.isAtAirport());
        
        List<AddressInfoType> address =  detail.getAddress();
        
        response.setAssressLine(StringUtils.join(address.get(0).getAddressLine(), ' '));
        response.setCityName(address.get(0).getCityName());
        response.setPostalCode(address.get(0).getPostalCode());
        response.setStateProv(address.get(0).getPostalCode());
        response.setCountryName(address.get(0).getCountryName().getCode());
        
        List<LocationTelephone> telephones = new ArrayList<LocationTelephone>();
        List<VehicleLocationDetailsType.Telephone> tels = detail.getTelephone();
        for(VehicleLocationDetailsType.Telephone tel : tels) {
            LocationTelephone telephone = new LocationTelephone();
            telephone.setCode(tel.getAreaCityCode());
            telephone.setType(tel.getPhoneLocationType());
            telephone.setNumber(tel.getPhoneNumber());
            telephones.add(telephone);
        }
        
        response.setTelephones(telephones);
        
        if(detail.getAdditionalInfo() != null && detail.getAdditionalInfo().getOperationSchedules() != null && !detail.getAdditionalInfo().getOperationSchedules().getOperationSchedule().isEmpty()) {
            List<LocationSchedule> schedules = new ArrayList<LocationSchedule>();
            List<OperationScheduleType> operationScheduleTypes = detail.getAdditionalInfo().getOperationSchedules().getOperationSchedule();
            for(OperationScheduleType operationScheduleType : operationScheduleTypes) {
                List<OperationScheduleType.OperationTimes.OperationTime> times = operationScheduleType.getOperationTimes().getOperationTime();
                for(OperationTime time : times) {
                    LocationSchedule locationSchedule = new LocationSchedule();
                    locationSchedule.setStart(time.getStart());
                    locationSchedule.setType(time.getText());
                    locationSchedule.setEnd(time.getEnd());
                    
                    if(time.isMon()) {
                        locationSchedule.setWeekDay("Mon");
                    } else if (time.isFri()) {
                        locationSchedule.setWeekDay("Fri");
                    } else if (time.isSat()) {
                        locationSchedule.setWeekDay("Sat");
                    } else if (time.isSun()) {
                        locationSchedule.setWeekDay("Sun");
                    } else if (time.isThur()) {
                        locationSchedule.setWeekDay("Thur");
                    } else if (time.isTue()) {
                        locationSchedule.setWeekDay("Tue");
                    } else if (time.isWeds()) {
                        locationSchedule.setWeekDay("Weds");
                    }
                    
                    schedules.add(locationSchedule);
                }
            }
            
            response.setSchedules(schedules);
        }
        
        
        List<SpecialEquipment> equipments = new ArrayList<SpecialEquipment>();
        List<VehicleLocationServicesOfferedType.SpecialEquipments.SpecialEquipment> specialEquipments = rs.getServicesOffered().getSpecialEquipments().getSpecialEquipment();
        for(VehicleLocationServicesOfferedType.SpecialEquipments.SpecialEquipment eq : specialEquipments) {
            SpecialEquipment specialEquipment = new SpecialEquipment();
            specialEquipment.setType(eq.getType());
            specialEquipment.setTitle(eq.getEquipDesc().getSubSection().get(0).getSubTitle());
            specialEquipment.setName(eq.getEquipDesc().getSubSection().get(0).getParagraph().get(0).getName());
            //specialEquipment.setContent());
            
            specialEquipment.setGuaranteedInd(eq.getEquipCharges().getEquipCharge().get(0).isGuaranteedInd());
            specialEquipment.setIncludedInRate(eq.getEquipCharges().getEquipCharge().get(0).isIncludedInRate());
            specialEquipment.setCurrencyCode(eq.getEquipCharges().getEquipCharge().get(0).getCurrencyCode());
            
            if(eq.getEquipCharges().getEquipCharge().get(0).getMinMax() != null) {
                specialEquipment.setMaxCharge(eq.getEquipCharges().getEquipCharge().get(0).getMinMax().getMaxCharge());
            }
            
            List<VehicleChargeType.Calculation> calculations = eq.getEquipCharges().getEquipCharge().get(0).getCalculation();
            
            for(VehicleChargeType.Calculation calculation : calculations) {
                if(calculation.getUnitName().equals("Hour")) {
                    specialEquipment.setHourCharge(calculation.getUnitCharge());
                } else if(calculation.getUnitName().equals("Day")) {
                    specialEquipment.setDayChagre(calculation.getUnitCharge());
                } else if(calculation.getUnitName().equals("Week")) {
                    specialEquipment.setWeekCharge(calculation.getUnitCharge());
                } else if(calculation.getUnitName().equals("Month")) {
                    specialEquipment.setMonthCharge(calculation.getUnitCharge());
                } else if(calculation.getUnitName().equals("RentalPeriod")) {
                    specialEquipment.setRentalPeriodCharge(calculation.getUnitCharge());
                }
            }
            
            equipments.add(specialEquipment);
            
        }
        
        response.setSpecialEquipments(equipments);
        
        return response;
    }
    
    
    /***
     * @author LZJ
     * 
     * ReservationCancle
     * 
     * 
     */
    
    
    /*
     * (non-Javadoc)
     * @see com.fita.api.handler.WebserviceHandler#cancelReservation(com.fita.api.dto.request.CancelExistingVehicleReservationRequest)
     */
    public VehicleReservationCancleResponse cancelReservation(CancelExistingVehicleReservationRequest request) throws JAXBException {
        
    	logger.info("cancle request data at [{}]", JsonUtils.toJson(request));
        
        // valid
        if (!request.isValid()) {
            throw BusinessException.newInstance("400", "请求参数不合法");
        }
        
        request.initialize(env);
        
        // call webService
        OTA30 otaService = this.generateOta30();
        OTAVehCancelRQ otaRequest = request.genecancelRq();
        
        JAXBContext context = JAXBContext.newInstance(OTAVehResRQ.class);
        Marshaller marshaller = context.createMarshaller();
        
        marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        
        
        //返回结果保存到xml
        Date date = new Date();
        String dateTime = DateFormatUtils.format(date, "yyyy-MM-dd&HH:mm:SS");
        logger.info("start search at [{}]", dateTime);
        marshaller.marshal(otaRequest, new File(filepath + "/CancelReservation/RVC_RQ_" + dateTime + ".xml"));
        OTAVehCancelRS rs = otaService.otaVehCancel(otaRequest);
        
        marshaller.marshal(rs, new File(filepath + "/CancelReservation/RVC_RS_" + dateTime + ".xml"));
        
        marshaller.marshal(otaRequest, System.out);
        
        
        
        logger.info("get rs [{}]", JsonUtils.toJson(rs));
        
        if(rs.getErrors() != null) {
            logger.error("Detail occurs error with rs [{}]", JsonUtils.toJson(rs));
            throw BusinessException.newInstance(rs.getErrors().getError().get(0).getCode(), rs.getErrors().getError().get(0).getValue());
        }
        
        
        VehicleReservationCancleResponse response  = this.generateVehCancelRSCore(rs);
        
        return response;
        
    }
    
    /**
     * 
     * @param rs
     * @return
     */
    private VehicleReservationCancleResponse generateVehCancelRSCore(OTAVehCancelRS rs) {
    	
    	
    	VehicleReservationCancleResponse response  = new VehicleReservationCancleResponse();
    	
    	
    	response.setCancelStatus(rs.getVehCancelRSCore().getCancelStatus().toString());
     
    	response.setType(rs.getVehCancelRSCore().getUniqueID().getType());
    	
    	response.setId(rs.getVehCancelRSCore().getUniqueID().getID());
    	
    	
    	return response;
    }
    
    
    
    

    /**
     * 
     * @return
     */
    private OTA30 generateOta30() {
        
        OTA30_Service service = new OTA30_Service();
        
        OTA30 ota30 = service.getPort(OTA30.class);
        
        BindingProvider bp = (BindingProvider) ota30;
        if(StringUtils.equalsAnyIgnoreCase(env, "Production")) {
            logger.info("user: {} psd: {} url: ", "OTA_CNHLTRPRD1", "k2KkGY2s", "https://xmldirect.ehi.com/services30/OTA30SOAP?WSDL");
            bp.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "OTA_CNHLTRPRD1");
            bp.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "k2KkGY2s");
            bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "https://xmldirect.ehi.com/services30/OTA30SOAP?WSDL");
        } else if(StringUtils.equalsAnyIgnoreCase(env, "Testing")) {
            logger.info("user: {} psd: {} url: ", "OTA_CNHLTRTST1", "hZ96nB3h", "https://cis1-xmldirect.ehi.com/services30/OTA30SOAP?WSDL");
            bp.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "OTA_CNHLTRTST1");
            bp.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "hZ96nB3h");
            bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "https://cis1-xmldirect.ehi.com/services30/OTA30SOAP?WSDL");
        }
        
        return ota30;
    }
}